package com.samphanie.auiu.biz.account

import android.app.Application
import android.content.Context
import android.content.Intent
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.samphanie.auiu.common.utils.LocalCache
import com.samphanie.auiu.http.ApiFactory
import com.samphanie.auiu.http.api.AccountApi
import com.samphanie.auiu.library.cache.AuiuStorage
import com.samphanie.auiu.library.executor.AuiuExecutor
import com.samphanie.auiu.library.restful.AuiuCallback
import com.samphanie.auiu.library.restful.AuiuResponse
import com.samphanie.auiu.library.utils.AppGlobals
import com.samphanie.auiu.model.TokenInfo
import com.samphanie.auiu.model.UserProfile

/**
 * @author ZSY
 */
object AccountManager {

    private const val JWT_TOKEN = "JWT_TOKEN"
    private const val JWT_TOKEN_PREFIX = "JWT_TOKEN_PREFIX"
    private const val USER_PROFILE_KEY = "user_profile"

    private var userProfile: UserProfile? = null

    private var tokenHeader: String? = null
    private var token: String? = null

    @Volatile
    private var isFetching = false

    private val loginLiveData = MutableLiveData<Boolean>()
    private val loginForeverObservers = mutableListOf<Observer<Boolean>>()

    private val profileLiveData = MutableLiveData<UserProfile>()
    private val profileForeverObservers = mutableListOf<Observer<UserProfile?>>()

    fun login(context: Context? = AppGlobals.get(), observer: Observer<Boolean>) {
        if (context is LifecycleOwner) {
            loginLiveData.observe(context, observer)
        } else {
            loginLiveData.observeForever(observer)
            loginForeverObservers.add(observer)
        }

        val intent = Intent(context, LoginActivity::class.java)
        if (context is Application) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        if (context == null) {
            throw IllegalStateException("context must not be null.")
        }

        context.startActivity(intent)
    }

    fun loginSuccess(data: TokenInfo) {
        LocalCache.getInstance().put(JWT_TOKEN, data.token)
        LocalCache.getInstance().put(JWT_TOKEN_PREFIX, data.tokenHead)
        this.tokenHeader = data.tokenHead
        this.token = data.token
        loginLiveData.value = true
        clearLoginForeverObservers()
    }

    private fun clearLoginForeverObservers() {
        for (observer in loginForeverObservers) {
            loginLiveData.removeObserver(observer)
        }
        loginForeverObservers.clear()
    }

    fun isLogin(): Boolean {
        return getAuthorization().isNotBlank()
    }

    fun getAuthorization(): String {
        if (token.isNullOrBlank() || tokenHeader.isNullOrBlank()) {
            token = LocalCache.getInstance().getString(JWT_TOKEN)
            tokenHeader = LocalCache.getInstance().getString(JWT_TOKEN_PREFIX)
        }
        return "$tokenHeader$token"
    }

    @Synchronized
    fun getUserProfile(lifecycleOwner: LifecycleOwner?, observer: Observer<UserProfile?>, onlyCache: Boolean) {
        if (lifecycleOwner == null) {
            profileLiveData.observeForever(observer)
            profileForeverObservers.add(observer)
        } else {
            profileLiveData.observe(lifecycleOwner, observer)
        }

        if (userProfile != null && onlyCache) {
            profileLiveData.postValue(userProfile)
            return
        }

        if (isFetching) return
        isFetching = true
        ApiFactory.create(AccountApi::class.java).profile()
            .enqueue(object : AuiuCallback<UserProfile> {
                override fun onSuccess(response: AuiuResponse<UserProfile>) {
                    if (response.successful() && response.data != null) {
                        userProfile = response.data

                        AuiuExecutor.executor(runnable = {
                            AuiuStorage.saveCache(USER_PROFILE_KEY, userProfile)
                            isFetching = false
                        })

                        profileLiveData.value = userProfile
                    } else {
                        profileLiveData.value = null
                    }
                    clearProfileForeverObservers()
                }

                override fun onFailed(throwable: Throwable) {
                    isFetching = false
                    profileLiveData.postValue(null)
                    clearProfileForeverObservers()
                }
            })
    }

    private fun clearProfileForeverObservers() {
        for (observer in profileForeverObservers) {
            profileLiveData.removeObserver(observer)
        }
        profileForeverObservers.clear()
    }

}